package org.xml.xpath4js.samples.client;

import java.util.HashMap;

import org.xml.xpath4js.client.EvalEngine;
import org.xml.xpath4js.client.XPathInput;
import org.xml.xpath4js.client.XPathSequence;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.http.client.*;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.ScriptElement;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.visualization.client.AbstractDataTable;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.Selection;
import com.google.gwt.visualization.client.AbstractDataTable.ColumnType;
import com.google.gwt.visualization.client.events.SelectHandler;
import com.google.gwt.visualization.client.visualizations.PieChart;
import com.google.gwt.visualization.client.visualizations.PieChart.Options;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class GoogleChartSampleLib implements EntryPoint {

	/**
     * @gwt.typeArgs <java.lang.String, com.google.gwt.http.client.Response>
     */	
	public static HashMap _responseMap = new HashMap();
	
	/**
     * @gwt.typeArgs <java.lang.String, Boolean>
     */	
	public static HashMap _statusMap = new HashMap();	
	
	private static String _error = "";
	
	//assigns the doChart method in this class to a native js variable in the window contex
	private final native void publish() /*-{
	  $wnd.doChart = this.@org.xml.xpath4js.samples.client.GoogleChartSampleLib::doChart(Ljava/lang/String;Ljava/lang/String;);
	}-*/;	

	public void onModuleLoad() {
		// ** need to stop IE from caching ajax loader script, otherwise will not load on refresh (fubar) 
		Document doc = Document.get();
		String src = "http://www.google.com/jsapi?callback=__gwt_AjaxLoader_onLoad" + "&x=" + ((int)(Math.random()*100));
		ScriptElement script = doc.createScriptElement();
		script.setSrc(src);
		script.setType("text/javascript");
		doc.getBody().appendChild(script);	
		// end fubar**
		
		publish();
	}	
	
	@SuppressWarnings("unused")
	private void doChart(final String url, String target) {
		
		final String outputTarget = target;
		
		RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));

		try {
		  Request request = builder.sendRequest(null, new RequestCallback() {
		    public void onError(Request request, Throwable exception) {
		       _error = "error";// Couldn't connect to server (could be timeout, SOP violation, etc.)     
		    }

		    @SuppressWarnings("unchecked")
			public void onResponseReceived(Request request, Response response) {
		    	_responseMap.put(url, response);
		    	_statusMap.put(url, false);
		    }
		  });
		} 
		catch (RequestException e) {
		  _error = "error";// Couldn't connect to server        
		}
		
		Timer t = new Timer() {
			public void run(){
				if(_responseMap.containsKey(url) && !((Boolean)_statusMap.get(url))){
					Response response = (Response) _responseMap.get(url);
			    	if (response.getStatusCode()==200) {
			    		final String chartxml = response.getText(); // Process the response in response.getText()
			  			if(chartxml!=""){
			  				Runnable onLoadCallback = new Runnable() {
			  					public void run() {
			  						Panel panel = RootPanel.get(outputTarget);
			  						
			  						//parse xml into xpath input sequence
			  						XPathSequence input  = new XPathSequence();
			  						input.AppendItem(new XPathInput(chartxml).XPathDoc);			  			
			  						
			  						// Create a pie chart visualization.
			  						PieChart pie = new PieChart(createTable(input), setupChart(input));
			  						pie.addSelectHandler(createSelectHandler(pie));
			  						panel.add(pie);
			  					}
			  				};
			  				// Load the visualization api, passing the onLoadCallback to be called
			  				// when loading is done.
			  				VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
			  			}
			    	} 
			    	else {
			    		_error = "error"; // Handle the error.  Can get the status text from response.getStatusText()
			    	}
			    	_statusMap.put(url, true);
				}
				else {
					this.schedule(500);
				}
			}
		};
		
		t.schedule(500);		

		if(_error!=""){
			HTML error = new HTML(_error);
			RootPanel.get().add(error);
		}
	}

	private Options setupChart(XPathSequence input) {
		
		String title =  EvalEngine.DoXPath(input, "/chart/def/title/text()").GetItemAt(0).GetStringValue();
		String width =  EvalEngine.DoXPath(input, "/chart/def/background/@width").GetItemAt(0).GetStringValue();
		String height = EvalEngine.DoXPath(input, "/chart/def/background/@height").GetItemAt(0).GetStringValue();
		
	    Options options = Options.create();
	    options.setTitle(title);
	    options.setWidth(Integer.parseInt(width));
	    options.setHeight(Integer.parseInt(height));
	    options.set3D(true);
	    options.setTitle(title);
	    
	    return options;
	}  

	private AbstractDataTable createTable(XPathSequence input) {
	    
		DataTable data = DataTable.create();
	    
		data.addColumn(ColumnType.STRING, "Task");
	    data.addColumn(ColumnType.NUMBER, "Hours per Day");
	    
	    XPathSequence dataitems = EvalEngine.DoXPath(input, "/chart/data/*");
    	XPathSequence labels = EvalEngine.DoXPath(dataitems, "/item/label/text()");
    	XPathSequence descriptions = EvalEngine.DoXPath(dataitems, "/item/desc/text()");    	
    	XPathSequence values = EvalEngine.DoXPath(dataitems, "/item/value/text()");

    	data.addRows(dataitems.GetSize());
	    for(int i=0; i<dataitems.GetSize();i++){
    		data.setValue(i, 0, labels.GetItemAt(i).GetStringValue() + " - " + descriptions.GetItemAt(i).GetStringValue());
    		data.setValue(i, 1, Integer.parseInt(values.GetItemAt(i).GetStringValue()));
	    }
	    return data;
	}	
	
	private SelectHandler createSelectHandler(final PieChart chart) {
		
		return new SelectHandler() {
			@Override
			public void onSelect(SelectEvent event) {
				
				String message = "";
				// May be multiple selections.
				JsArray<Selection> selections = chart.getSelections();
				for (int i = 0; i < selections.length(); i++) {
					//add a new line for each selection
					message += i == 0 ? "" : "\n";
	        
					Selection selection = selections.get(i);
					if (selection.isCell()) {
						//isCell() returns true if a cell has been selected.
						// getRow() returns the row number of the selected cell.
						int row = selection.getRow();
						//getColumn() returns the column number of the selected cell.
						int column = selection.getColumn();
						message += "cell " + row + ":" + column + " selected";
					}
					else if (selection.isRow()) {
						// isRow() returns true if an entire row has been selected.
						// getRow() returns the row number of the selected row.
						int row = selection.getRow();
						message += "row " + row + " selected";
					}
					else {
						//unreachable
						message += "Pie chart selections should be either row selections or cell selections.";
						message += "  Other visualizations support column selections as well.";
					}
				}
				//Window.alert(message);
			}
		};
	}



}
	

